package com.hyt.it.ogt.kq.service.gov.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hyt.core.base.BaseServiceImpl;
import com.hyt.core.util.UUIDUtils;
import com.hyt.it.ogt.kq.common.config.exception.KqException;
import com.hyt.it.ogt.kq.common.gov.constant.ResponseCode;
import com.hyt.it.ogt.kq.common.gov.utils.timeslot.Timeslot;
import com.hyt.it.ogt.kq.common.gov.utils.timeslot.TimeslotUtil;
import com.hyt.it.ogt.kq.service.gov.mapper.TimeRoomExcludeMapper;
import com.hyt.it.ogt.kq.service.gov.model.dto.TimeRoomInfoDTO;
import com.hyt.it.ogt.kq.service.gov.model.entity.TaskRoom;
import com.hyt.it.ogt.kq.service.gov.model.entity.Time;
import com.hyt.it.ogt.kq.service.gov.model.entity.TimeRoomExclude;
import com.hyt.it.ogt.kq.service.gov.model.vo.TaskRoomToTimeParamVO;
import com.hyt.it.ogt.kq.service.gov.model.vo.TaskTimeRoomArrangeOrNoVO;
import com.hyt.it.ogt.kq.service.gov.service.ITaskRoomService;
import com.hyt.it.ogt.kq.service.gov.service.ITimeRoomExcludeService;
import com.hyt.it.ogt.kq.service.gov.service.ITimeService;
import com.hyt.loginfo.model.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @PACKAGE_NAME: com.hyt.it.ogt.kq.service.gov.service.impl
 * @USER: Wuyingge
 * @DATE: 2023/8/23 11:58
 * @PROJECT_NAME: it-ogt-kq
 * @Desc :
 **/
@Service
@Slf4j
public class TimeRoomExcludeServiceImpl extends BaseServiceImpl<TimeRoomExcludeMapper, TimeRoomExclude> implements ITimeRoomExcludeService {

    @Resource
    private ITaskRoomService iTaskRoomService;
    @Resource
    private ITimeService iTimeService;

    /**
     * 批次绑定考场
     *
     * @param taskRoomToTimeParamVO
     * @param user
     */
    @Override
    public void createTimeRoom(TaskRoomToTimeParamVO taskRoomToTimeParamVO, User user) {
        String taskId = taskRoomToTimeParamVO.getTaskId();
        String timeId = taskRoomToTimeParamVO.getTimeId();

        List<TaskTimeRoomArrangeOrNoVO> taskTimeRoomArrangeOrNoVOList = taskRoomToTimeParamVO.getTaskTimeRoomArrangeOrNoVOList();

        //如果是空，则全部取消
        if (CollectionUtils.isEmpty(taskTimeRoomArrangeOrNoVOList)) {
            LambdaUpdateWrapper<TimeRoomExclude> timeRoomLambdaUpdateWrapper = Wrappers.lambdaUpdate();
            timeRoomLambdaUpdateWrapper.eq(TimeRoomExclude::getTaskId,taskId)
                    .eq(TimeRoomExclude::getTimeId,timeId)
                    .eq(TimeRoomExclude::getDelFlag,false)
                    .set(TimeRoomExclude::getDelFlag,true);
            this.update(timeRoomLambdaUpdateWrapper);
            return;
        }

        //取出roomId
        //List<String> roomIds = taskRoomToTimeParamVO.getTaskTimeRoomArrangeOrNoVOList().stream().map(TaskTimeRoomArrangeOrNoVO::getRoomId).collect(Collectors.toList());
        //List<TaskTimeRoomArrangeOrNoVO> vos = taskRoomMapper.selectTimeRoomByTaskIdAndTimeId(taskId,timeId,roomIds);
        //查询已考场数据
        LambdaQueryWrapper<TimeRoomExclude> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(TimeRoomExclude::getTaskId,taskId)
                .eq(TimeRoomExclude::getTimeId,timeId)
                .eq(TimeRoomExclude::getDelFlag,false);
        List<TimeRoomExclude> timeRoomList = baseMapper.selectList(queryWrapper);
        StringBuilder roomBuilder = new StringBuilder();
        timeRoomList.stream().forEach(timeRoom -> {
            roomBuilder.append(timeRoom.getRoomId()).append(",");
        });

        //批次绑定考场时，校验相同考场中是否有批次时间冲突的批次
        //this.hasTimeOverlap(taskRoomToTimeParamVO);

        //新增绑定考场
        List<TimeRoomExclude> addTimeRoomList = new ArrayList<>();
        StringBuilder delRoomBuilder = new StringBuilder();
        int code = this.getLastTimeRoomCode(taskId);

        for (TaskTimeRoomArrangeOrNoVO taskTimeRoomArrangeOrNoVO : taskTimeRoomArrangeOrNoVOList) {
            if (!roomBuilder.toString().contains(taskTimeRoomArrangeOrNoVO.getRoomId())) {
                TimeRoomExclude timeRoom = new TimeRoomExclude();
                code = code + 1;
                timeRoom.setTaskId(taskId)
                        .setTimeId(timeId)
                        .setRoomId(taskTimeRoomArrangeOrNoVO.getRoomId())
                        .setMaxCount(Integer.parseInt(taskTimeRoomArrangeOrNoVO.getSeatNum()))
                        .setPlanCount(Integer.parseInt(taskTimeRoomArrangeOrNoVO.getPlanCount()))
                        .setActualCount(0)
                        //.setSelectType(taskRoomToTimeParamVO.getSelectType())
                        .setCode(String.valueOf(code))
                        .setId(UUIDUtils.newSortUUID());
                timeRoom.setOfficeId(user.getOfficeid())
                        .setDeptId(user.getOrganizationid());
                addTimeRoomList.add(timeRoom);
            }
            delRoomBuilder.append(taskTimeRoomArrangeOrNoVO.getRoomId()).append(",");
        }
        if (!CollectionUtils.isEmpty(addTimeRoomList)) {
            this.saveBatch(addTimeRoomList);
        }

        //删除绑定的考场
        List<String> delTimeRoomList = new ArrayList<>();
        timeRoomList.stream().forEach(timeRoom -> {
            //如果已经编排了，则不允许删除
            if (!delRoomBuilder.toString().contains(timeRoom.getRoomId()) && timeRoom.getActualCount() == 0) {
                delTimeRoomList.add(timeRoom.getId());
            }
        });

        if (!CollectionUtils.isEmpty(delTimeRoomList)) {
            LambdaUpdateWrapper<TimeRoomExclude> timeRoomLambdaUpdateWrapper = Wrappers.lambdaUpdate();
            timeRoomLambdaUpdateWrapper.in(TimeRoomExclude::getId,delTimeRoomList)
                    .set(TimeRoomExclude::getDelFlag,true);
            this.update(timeRoomLambdaUpdateWrapper);
        }
    }

    /**
     * 批次绑定考场时，校验相同考场中是否有批次时间冲突的批次
     * @param taskRoomToTimeParamVO 批次绑定考场参数
     */
    private void hasTimeOverlap(TaskRoomToTimeParamVO taskRoomToTimeParamVO) {
        //1、获取当前批次绑定的场次信息（包括“已绑定的”和“将要绑定的”）
        //获取当前批次已绑定的场次信息
        List<TimeRoomInfoDTO> timeRoomInfoDTOList = baseMapper.listTimeRoomInfoDTO(taskRoomToTimeParamVO.getTaskId(),
                taskRoomToTimeParamVO.getTimeId(), null);
        //获取当前批次将要绑定的场次信息
        List<String> roomIdList = taskRoomToTimeParamVO.getTaskTimeRoomArrangeOrNoVOList().stream()
                .map(TaskTimeRoomArrangeOrNoVO::getRoomId)
                .collect(Collectors.toList());
        List<TaskRoom> taskRoomList = iTaskRoomService.lambdaQuery()
                .in(TaskRoom::getPtRoomId, roomIdList)
                .eq(TaskRoom::getTaskId, taskRoomToTimeParamVO.getTaskId())
                .eq(TaskRoom::getDelFlag, Boolean.FALSE)
                .list();
        Time time = iTimeService.lambdaQuery()
                .eq(Time::getId, taskRoomToTimeParamVO.getTimeId())
                .eq(Time::getTaskId, taskRoomToTimeParamVO.getTaskId())
                .eq(Time::getDelFlag, Boolean.FALSE)
                .last("LIMIT 1")
                .one();
        //合并当前批次绑定的场次信息
        taskRoomList.forEach(room -> {
            TimeRoomInfoDTO timeRoomInfoDTO = new TimeRoomInfoDTO();
            timeRoomInfoDTO.setRoomId(room.getId())
                    .setRoomName(room.getName())
                    .setTimeId(time.getId())
                    .setTimeName(time.getName())
                    .setStartTime(time.getStartTime())
                    .setEndTime(time.getEndTime());
            timeRoomInfoDTOList.add(timeRoomInfoDTO);
        });
        //2、获取当前批次绑定的考场所对应的其他批次的场次信息（即：[当前批次]绑定[考场1]，[批次2]绑定[考场1]，获取[批次2]绑定[考场1]的场次信息）
        //获取当前批次绑定的考场id
        String roomIds = timeRoomInfoDTOList.stream()
                .map(TimeRoomInfoDTO::getRoomId)
                .distinct()
                .collect(Collectors.joining(","));
        //根据当前批次绑定的考场id，获取当前批次绑定的考场所对应的其他批次的场次信息
        List<TimeRoomInfoDTO> othersTimeRoomInfoDTOList = baseMapper
                .listTimeRoomInfoDTO(taskRoomToTimeParamVO.getTaskId(), null, roomIds);
        //过滤掉当前批次的场次信息
        List<TimeRoomInfoDTO> othersList = othersTimeRoomInfoDTOList.stream()
                .filter(other -> !other.getTimeId().equals(taskRoomToTimeParamVO.getTimeId()))
                .collect(Collectors.toList());
        //3、遍历步骤1中当前批次绑定的场次信息，找出步骤2中是否存在考场id相同 且 批次时间与当前批次时间重叠的场次
        //构造当前批次的时间段
        Timeslot timeslot = TimeslotUtil.buildSlot(time.getStartTime(), time.getEndTime());
        //创建用于存放批次时间重叠的Map，TimeRoomInfoDTO是当前批次下的场次信息，List<TimeRoomInfoDTO>是与当前批次绑定了相同考场 且批次时间与当前批次时间重叠的场次信息
        Map<TimeRoomInfoDTO, List<TimeRoomInfoDTO>> overlappedMap = new HashMap<>();
        timeRoomInfoDTOList.forEach(timeRoomInfoDTO -> {
            //筛选出考场id与当前场次相同、且批次时间段与当前场次重叠的场次
            List<TimeRoomInfoDTO> list = othersList.stream().filter(other -> {
                if (other.getRoomId().equals(timeRoomInfoDTO.getRoomId())) {
                    //构造当前遍历批次时间段
                    Timeslot currentTimeslot = TimeslotUtil.buildSlot(other.getStartTime(), other.getEndTime());
                    //判断当前批次和当前遍历批次的时间段是否重叠
                    return TimeslotUtil.overlapped(timeslot, currentTimeslot);
                }
                return false;
            }).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(list)) {
                overlappedMap.put(timeRoomInfoDTO, list);
            }
        });

        if (!CollectionUtils.isEmpty(overlappedMap)) {
            //当前批次中绑定的考场“考场X”已被批次“批次A、批次B、批次C”绑定，且当前批次与批次“批次A、批次B、批次C”的时间冲突
            List<String> messageList = overlappedMap.entrySet().stream().map(entry -> {
                //获取时间重叠的批次名称
                String timeNames = entry.getValue().stream()
                        .map(TimeRoomInfoDTO::getTimeName)
                        .collect(Collectors.joining("、"));

                return "当前批次中绑定的考场" + "【" + entry.getKey().getRoomName()
                        + "】" + "已被批次" + "【" + timeNames + "】" + "绑定，且当前批次与批次"
                        + "【" + timeNames + "】" + "的时间冲突;";
            }).collect(Collectors.toList());
            throw new KqException(ResponseCode.TIMES_OVERLAP.getCode(), ResponseCode.TIMES_OVERLAP.getMsg(), messageList);
        }
    }

    /**
     * 获取当前最大场次编号
     * @param taskId 考试任务id
     * @return 当前最大场次编号
     */
    private int getLastTimeRoomCode(String taskId) {
        QueryWrapper<TimeRoomExclude> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .select(TimeRoomExclude::getCode)
                .eq(TimeRoomExclude::getTaskId, taskId)
                .eq(TimeRoomExclude::getDelFlag, false)
                .last("ORDER BY CAST(code AS SIGNED) DESC LIMIT 1");
        TimeRoomExclude timeRoom = getOne(queryWrapper);
        String code = Optional.ofNullable(timeRoom)
                .map(TimeRoomExclude::getCode)
                .orElse("0");
        return Integer.parseInt(code);
    }

}
